package redtankface.tasks;

import redtankface.*;

import static robocode.util.Utils.normalRelativeAngle;

/**
 * Задача лобового движения на противника
 */
public class AttackMoveTask extends AbstractTankChooseTask  {
	/** Вес расстояния при наступлении. Чем больше, тем радостнее едем впирёт */
	private static final double ATTACK_DISTANCE_WEIGHT = 2;
	/** Вес поворота корпуса танка. Чем больше, тем ленивее нам поворачивать */
	private static final double ATTACK_TANK_TURN_WEIGHT = 25;
	/** Вес поворота пушки (с учетом поворта танка). Чем больше, тем ленивее будет крутить пушкой после нападения на врага */
	private static final double ATTACK_GUN_TURN_WEIGHT = 10;
	/** Лучшее расстояние для атаки */
	private static final double BEST_ATTACK_DISTANCE = 200;
	/** Чем больше мы не ехали вперед, тем нам больше этого хочется */
	private static final long AGE_WEIGHT = 15;
	/** Штраф за приближение к стенам. Чем больше, тем сильнее мы туда не хотим */
	private static final double NO_WALLS_WEIGHT = 500;
	/** Минимальная дистанция приближения к стене. После неё наступит штраф */
	private static final double WALL_MIN_DISTANCE = 200;
	private final double ANGLE_MOVE_VALUE;

	/**
	 * Угол, на который вводится поправка
	 * @param aRobot
	 * @param aAngleMoveValue
	 */
	public AttackMoveTask(RedTankFace aRobot, double aAngleMoveValue) {
		super(aRobot);
		ANGLE_MOVE_VALUE = aAngleMoveValue;
	}

	@Override
	protected long getLocalRating(EnemyInfo aEnemy, double distance, double heading) {
		TankCoordinates myPos = mRobot.getCoord();
		TankCoordinates enPos =  aEnemy.getCoord(mRobot.getTime());
		// Если дистанция меньше рекомендованной, то не подъезжаем
		if (distance < BEST_ATTACK_DISTANCE)
			return 0;

		// На какой угол надо повернуть танк, чтобы поехать на противника (может быть отрицательное)
		double tankTurnAngle = normalRelativeAngle(heading - Math.toRadians(mRobot.getHeading()));
		// На какой угол потом надо будет довернуть пушку, чтобы она смотрела на врага
		double gunTurnAngle = normalRelativeAngle(Math.toRadians(mRobot.getGunHeading()) - tankTurnAngle);

		double cost = distance * ATTACK_DISTANCE_WEIGHT;
		cost -= Math.abs(tankTurnAngle) * ATTACK_TANK_TURN_WEIGHT;
		cost -= Math.abs(gunTurnAngle) * ATTACK_GUN_TURN_WEIGHT;
		cost += getTimeFromLastUse() * AGE_WEIGHT;
		if (TankUtils.getDistanceToWall(mRobot.getCoord(), heading + ANGLE_MOVE_VALUE, mRobot) < WALL_MIN_DISTANCE) {
			cost -= NO_WALLS_WEIGHT;
		}
		return (long)cost;
	}

	@Override
	public void p_doTask() {
		mRobot.doTurnTank(bestEnemy.getCoord(mRobot.getTime()), ANGLE_MOVE_VALUE);
		mRobot.ahead(calcAttackDistance());
	}

	/**
	 * Вычисляет дистанцию, на которую есть смысл подойти к противнику
	 */
	private double calcAttackDistance() {
		double distance = TankUtils.getDistance(bestEnemy.getCoord(mRobot.getTime()), mRobot.getCoord());
		distance -= BEST_ATTACK_DISTANCE;
		return distance;
	}
}
